/*
 * Ethan Levine
 * 
 * The contents of this file are subject to the GNU General Public
 * License (GPL) v2.  The full contents of this license can be
 * found at Mathma's website, http://www.codeplex.com/mathma/license
 */
package mathma.core.calc;

import mathma.core.real.InfiniteReal;
import mathma.core.real.Real;
import mathma.core.form.UnknownSuspensionException;
import mathma.core.expr.Variable;
import mathma.core.expr.VariableMapping;
import mathma.core.expr.Expression;
import mathma.core.form.SuspendedExpression;

import java.util.List;
import java.util.ArrayList;

/**
 * @since 0.1.4
 * @author Ethan Levine
 */
public class SumExpression extends SuspendedExpression<Real, Real> {

    private Expression<Real> operand;
    private Variable<Real> i;
    private Real start;
    private Real end;

    public SumExpression(Expression<Real> operand, Variable<Real> i,
            Real start) {
        super(Real.Type);
        if (!start.isInteger()) {
            throw new IllegalArgumentException(
                    "SumExpression.start must be an integer.");
        }
        this.operand = operand;
        this.i = i;
        this.start = start;
        this.end = InfiniteReal.POSITIVE_INFINITY;
    }

    public SumExpression(Expression<Real> operand, Variable<Real> i,
            Real start, Real end) {
        super(operand.getType());
        if (!start.isInteger()) {
            throw new IllegalArgumentException(
                    "SumExpression.start must be an integer.");
        }
        if (!end.isInteger() && !end.isInfinite()) {
            throw new IllegalArgumentException(
                    "SumExpression.end must be an integer or infinite.");
        }
        this.operand = operand;
        this.i = i;
        this.start = start;
        this.end = end;
    }

    public Expression<Real> getOperand() {
        return operand;
    }
    
    public Variable<Real> getVariable() {
        return i;
    }
    
    public Real getStart() {
        return start;
    }
    
    public Real getEnd() {
        return end;
    }
    
    // TODO - implement
    @Override
    public Expression<Real> calculate() throws UnknownSuspensionException {
        return null;
    }
    
    @Override
    public SumExpression newInstance(List<Expression<Real>> operands) {
        if (operands.size() == 4 &&
                Variable.class.isAssignableFrom(operands.get(1).getClass())
                && Real.class.isAssignableFrom(operands.get(2).getClass())
                && Real.class.isAssignableFrom(operands.get(3).getClass())) {
            return new SumExpression(operands.get(0), (Variable<Real>)
                    operands.get(1), (Real) operands.get(2), (Real) operands.get(3));
        } else {
            throw new IllegalArgumentException("Invalid argument to SumExpression.newInstance(List<Expression<Real>>).");
        }
    }
    
    @Override
    public List<Expression<Real>> getOperands() {
        List<Expression<Real>> operands = new ArrayList<Expression<Real>>();
        operands.add(operand);
        operands.add(i);
        operands.add(start);
        operands.add(end);
        return operands;
    }

    @Override
    public Expression<Real> differentiate(Variable<Real> var) {
        try {
            return calculate().differentiate(var);
        } catch (UnknownSuspensionException e) {
            return new DerivativeExpression(this, var);
        }
    }
}
